package org.hdax.dm.service.impl;

import com.rabbitmq.client.Channel;
import org.hda.dm.utils.IdWorker;
import org.hda.dm.utils.exception.DmException;
import org.hdax.dm.client.*;
import org.hdax.dm.entity.item.DmItem;
import org.hdax.dm.entity.linkuser.LinkUser;
import org.hdax.dm.entity.order.DmOrder;
import org.hdax.dm.entity.order.DmOrderLinkUser;
import org.hdax.dm.entity.scheduler_seat.DmSchedulerSeat;
import org.hdax.dm.entity.scheduler_seat_price.DmSchedulerSeatPrice;
import org.hdax.dm.request.CreateOrderRequest;
import org.hdax.dm.service.OrderService;
import org.hdax.dm.utils.RedisUtil;
import org.hdax.dm.vo.CommonResponse;
import org.hdax.dm.vo.VoUtil;
import org.hdax.dm.vo.constants.ConstantsData;
import org.springframework.amqp.AmqpException;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageDeliveryMode;
import org.springframework.amqp.core.MessagePostProcessor;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Service
public class OrderServiceImpl implements OrderService {

    @Autowired
    private DmItemClient dmItemClient;

    @Autowired
    private DmSchedulerSeatClient dmSchedulerSeatClient;

    @Autowired
    private DmSchedulerSeatPriceClient dmSchedulerSeatPriceClient;

    @Autowired
    private DmOrderClient dmOrderClient;

    @Autowired
    private LinkUserClient dmLinkUserClient;

    @Autowired
    private DmOrderLinkUserClient dmOrderLinkUserClient;

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Autowired
    private RedisUtil redisUtil;

    @Override
    public CommonResponse<Long> createOrder(CreateOrderRequest createOrderRequest) throws Exception {
        //查询当前订单管理的商品信息是否存在
        DmItem dmItem = dmItemClient.findById(createOrderRequest.getItemId().intValue());
        if (dmItem == null) {
            throw new Exception("要下单的商品不存在");
        }
        //生成订单编号
        String orderNo = IdWorker.getId();
        //订单作为信息拆分
        String[] seatArrays = createOrderRequest.getSeatPositions().split(",");


        //临时锁定当前剧场(排期)
        //Redis
        //false 剧场被锁定 当前下单人要等待
        //true 剧场被当前下单人锁定 可以正常执行
        while (!redisUtil.lock(String.valueOf(createOrderRequest.getSchedulerId()))) {
            TimeUnit.SECONDS.sleep(1);
        }


        //查询座位是否被锁定(redis)
        boolean isLock = false;
        for (int i = 0; i < seatArrays.length; i++) {
            if (redisUtil.get(String.valueOf(createOrderRequest.getSchedulerId()).concat(":").concat(seatArrays[i])) != null) {
                isLock = true;
            }
        }

        if (isLock) {
            //剧场解锁
            redisUtil.unlock(String.valueOf(createOrderRequest.getSchedulerId()));
            throw new DmException("座位已经被别人锁定");
        }
        //总票价
        Double totalAmount = 0D;
        //存储订单中每一个座位的票价
        Double[] doublePrices = new Double[seatArrays.length];
        DmSchedulerSeat schedulerSeat = null;
        for (int i = 0; i < seatArrays.length; i++) {
            //拆分座位的横纵坐标
            String[] seats = seatArrays[i].split("_");
            //查询当前作为的排期状态
            schedulerSeat = dmSchedulerSeatClient.getSchedulerSeatByOrder(
                    createOrderRequest.getSchedulerId().intValue(),
                    Integer.parseInt(seats[0]),
                    Integer.parseInt(seats[1])
            );
            //锁定当前座位
            schedulerSeat.setStatus(ConstantsData.SchedulerSeatStatus.SchedulerSeat_TOPAY);
            //更新下单用户
            schedulerSeat.setUserId(createOrderRequest.getUserId().intValue());
            //添加作为信息到数据库
            dmSchedulerSeatClient.modifySchedulerSeat(schedulerSeat);
            //计算总票价
            DmSchedulerSeatPrice schedulerSeatPrice = dmSchedulerSeatPriceClient.getSchedulerSeatPriceBySchedulerIdAndArea(createOrderRequest.getSchedulerId().intValue(),
                    schedulerSeat.getAreaLevel());
            totalAmount += schedulerSeatPrice.getPrice();
            doublePrices[i] = schedulerSeatPrice.getPrice();
        }
        //生成订单信息
        DmOrder dmOrder = new DmOrder();
        dmOrder.setOrderNo(orderNo);
        //将请求中的部分信息添加到订单中
        BeanUtils.copyProperties(createOrderRequest, dmOrder);
        dmOrder.setItemName(dmItem.getItemName());
        dmOrder.setOrderType(ConstantsData.SchedulerSeatStatus.SchedulerSeat_TOPAY);
        dmOrder.setTotalCount(seatArrays.length);
        //如果勾选了保险，则增加到中金额
        if (createOrderRequest.getIsNeedInsurance() == ConstantsData.OrderStatus.ISNEEDINSURANCE_YES) {
            dmOrder.setInsuranceAmount(ConstantsData.OrderStatus.NEEDINSURANCE_MONEY);
        }


//        设置异常捕获
        try {
            //添加订单
            //如果异常  之前新增的座位信息要回滚
            dmOrderClient.addOrder(dmOrder);
        } catch (Exception e) {
            //重置座位信息
            sendResetSeatMsg(schedulerSeat.getScheduleId().longValue(), seatArrays);
            e.printStackTrace();
        }

        //新增订单用户信息
        String[] linkIds = createOrderRequest.getLinkIds().split(",");
        for (int i = 0; i < linkIds.length; i++) {
            //查询联系人用户信息
            LinkUser linkUser = dmLinkUserClient.findLinkUserById(Long.parseLong(linkIds[i]));
            DmOrderLinkUser orderLinkUser = new DmOrderLinkUser();
            orderLinkUser.setOrderId(Long.parseLong(orderNo));
            orderLinkUser.setLinkUserId(Long.parseLong(linkIds[i]));
            orderLinkUser.setLinkUserName(linkUser.getName());
            orderLinkUser.setPrice(doublePrices[i]);
            orderLinkUser.setX(Integer.parseInt(seatArrays[i].split("_")[0]));
            orderLinkUser.setY(Integer.parseInt(seatArrays[i].split("_")[1]));
            dmOrderLinkUserClient.addOrderLinkUser(orderLinkUser);
        }
        return VoUtil.returnSuccess(orderNo);
    }
    //锁定座位
    private void setLockSeat(String scheduleId, String[] seatArrays) {
        for (int i = 0; i < seatArrays.length; i++) {
            redisUtil.set(scheduleId.concat(":").concat(seatArrays[i]),"lock");
        }
        //解锁剧场
        redisUtil.unlock(String.valueOf(scheduleId));
    }

    private void sendDelLinkUser(String orderNo) {
        rabbitTemplate.convertAndSend(ConstantsData.RabbitMQName.TOPIC_EXCHANGE,
                ConstantsData.RabbitMQName.TO_RESET_LINKUSER_QUEUE,
                orderNo,
                new MessagePostProcessor() {
                    @Override
                    public Message postProcessMessage(Message message) throws AmqpException {
                        message.getMessageProperties().setDeliveryMode(MessageDeliveryMode.PERSISTENT);
                        return message;
                    }
                });
    }

    //    监听消息并删除订单联系人
    @RabbitListener(queues = ConstantsData.RabbitMQName.TO_RESET_LINKUSER_QUEUE)
    private void delLinkUser(String orderNo, Message message, Channel channel) {
        try {
            dmOrderLinkUserClient.delLinkUser(Long.parseLong(orderNo));
        } catch (Exception e) {
            try {
                channel.basicNack(message.getMessageProperties().getDeliveryTag(), false, false);
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }
    }

    //    这里是增加订单用户信息的时候出错  需要进行向rabbitMQ发送一个消息来进行回滚消费
    private void sendDelOrderMsg(String orderNo) {
//        向rabbitMQ发送一条消息进行监听回滚
        rabbitTemplate.convertAndSend(ConstantsData.RabbitMQName.TOPIC_EXCHANGE,
                ConstantsData.RabbitMQName.TO_DEL_ORDER_QUEUE,
                orderNo,
                new MessagePostProcessor() {
                    @Override
                    public Message postProcessMessage(Message message) throws AmqpException {
                        message.getMessageProperties().setDeliveryMode(MessageDeliveryMode.PERSISTENT);
                        return message;
                    }
                });
    }

    //    进行监听消息队列 (删除订单联系人)
    @RabbitListener(queues = ConstantsData.RabbitMQName.TO_DEL_ORDER_QUEUE)
    private void delOrderMsg(String orderNo, Message message, Channel channel) {
        //删除订单
        try {
            dmOrderClient.delOrder(orderNo);
        } catch (Exception e) {
            try {
                channel.basicNack(message.getMessageProperties().getDeliveryTag(), false, false);
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }
    }


    //    这里是添加订单的时候出错  需要进行向rabbitMQ发送一个消息来进行回滚消费
    private void sendResetSeatMsg(Long scheduleId, String[] seatArrays) {
//        把将要消费的数据放入Map集合中
        Map<String, Object> map = new HashMap<>();
        map.put("scheduleId", scheduleId);
        map.put("seatArrays", seatArrays);

        //发送消息到队列 (主题模式)
        //exchange, routingkey(queue)
        rabbitTemplate.convertAndSend(ConstantsData.RabbitMQName.TOPIC_EXCHANGE,
                ConstantsData.RabbitMQName.TO_RESET_SEAT_QUEUE,
                map,
                new MessagePostProcessor() {
                    @Override
                    public Message postProcessMessage(Message message) throws AmqpException {
                        message.getMessageProperties().setDeliveryMode(MessageDeliveryMode.PERSISTENT);
                        return message;
                    }
                });
    }

    //    进行监听消息队列 (重置座位信息)
    @RabbitListener(queues = ConstantsData.RabbitMQName.TO_RESET_SEAT_QUEUE)
    public void resetSeatMsg(Map<String, Object> map, Message message, Channel channel) {
        //获取排期编号
        Long schedulerId = (Long) map.get("scheduleId");
        //获取座位集合
        String[] seatArrays = (String[]) map.get("seatArrays");

//        接下来进行数据回滚
        for (int i = 0; i < seatArrays.length; i++) {

            String[] seats = seatArrays[i].split("_");
            DmSchedulerSeat schedulerSeat = dmSchedulerSeatClient.getSchedulerSeatByOrder(
                    schedulerId.intValue(),
                    Integer.parseInt(seats[0]),
                    Integer.parseInt(seats[1])
            );

            //数据回滚修改
            //锁定当前座位
            schedulerSeat.setStatus(1);
            //更新下单用户
            schedulerSeat.setUserId(null);
            //设置订单号
            schedulerSeat.setOrderNo(null);
            try {
                dmSchedulerSeatClient.modifySchedulerSeat(schedulerSeat);
            } catch (Exception e) {
                try {
                    //消息持久化索引   是否批量   是否拒绝重新加入队列
                    channel.basicNack(message.getMessageProperties().getDeliveryTag(), false, false);
                } catch (IOException ex) {
                    ex.printStackTrace();
                }
            }
        }
    }
}
